from django.db import transaction
from django.db.models import Q
from django.forms import model_to_dict
from django.shortcuts import get_object_or_404
from rest_framework import status
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.exceptions import ValidationError
from rest_framework.response import Response
from rest_framework_simplejwt.authentication import JWTAuthentication

from apps.client.models import Client
from apps.client.types import MessagingStatusChoices
from apps.communication.models import ProviderClientMessage, MessageFile
from apps.communication.signals import client_message, provider_message
from apps.communication.types import FromTypes
from apps.core.image_uploader import ImageUpload
from apps.core.pagination import paginated_queryset_response
from apps.users.permissions import IsProvider, IsClient


@api_view(('GET', 'POST'))
@authentication_classes([JWTAuthentication])
@permission_classes([IsProvider | IsClient])
@transaction.atomic
def message_api(request):
    if request.method == 'POST':
        user = request.user
        data = request.data

        if user.is_client:
            if user.client.messaging == MessagingStatusChoices.ACTIVE.value:
                data['client'] = user.client
                data['from_type'] = FromTypes.CLIENT.value
            else:
                raise ValidationError('You are not allowed to message your provider yet')
        elif user.is_provider:
            id = data['client']
            client = Client.objects.filter(id=id).first()
            data['client'] = client
            if client.messaging == MessagingStatusChoices.ACTIVE.value:
                data['from_type'] = FromTypes.PROVIDER.value
            else:
                raise ValidationError('Please update client messaging status to active')


        files = request.FILES

        message = ProviderClientMessage.objects.create(**data)
        if files:
            for file in files:
                file_uri = ImageUpload.upload_image(files.get(file), 'message', str(message.pk), files.get(file).name)
                message_file = MessageFile.objects.create(message=message, message_file=file_uri.split("?")[0],
                                                          file_name=files.get(file).name)
                message_file.save()

        if user.is_client:
            client_message.send(sender=message, instance=message)
        if user.is_provider:
            provider_message.send(sender=message, instance=message)
        return Response(model_to_dict(message), status=status.HTTP_201_CREATED)

    if request.method == 'GET':
        user = request.user
        queryset = ProviderClientMessage.objects.all().order_by('-created_at')
        if user.is_client:
            queryset = queryset.filter(client=user)

        if user.is_provider:
            params = request.query_params

            if 'client' in params:
                queryset = queryset.filter(
                    Q(created_by=user) |
                    Q(created_by=params['client']))

        messages = list()
        for query in queryset:
            files = query.files.values('message_file', 'file_name')
            query = model_to_dict(query, fields=['client', 'id', 'content', 'message_type', 'from_type'])
            query['files'] = files
            messages.append(query)

        return paginated_queryset_response(messages, request)





@api_view(['GET', 'POST'])
@authentication_classes([JWTAuthentication])
@permission_classes([IsProvider | IsClient])
@transaction.atomic
def messages_api(request):
    if request.method == 'GET':
        user = request.user
        queryset = ProviderClientMessage.objects.all()
        if user.is_client:
            queryset = queryset.filter(client=user)
        elif user.is_provider:
            params = request.query_params
            client_id = params.get('client', None)
            if client_id:
                queryset = queryset.filter(client__id=client_id)

        data = []
        for message in queryset.order_by('-created_at'):
            data.append({
                'id': message.id,
                'updated_at': message.updated_at.timestamp(),
                'created_at': message.created_at.timestamp(),
                'content': message.content,
                'files': [{
                    'file_url': file.message_file,
                    'file_name': file.file_name
                } for file in message.files.all()],
                'client': message.client.id,
                'message_type': message.message_type,
                'from_type': message.from_type,
                'is_read': message.is_read
            })

        return paginated_queryset_response(data, request)
    if request.method == 'POST':
        user = request.user
        mutable = request.POST._mutable

        if not mutable:
            request.POST._mutable = True

        if user.is_client:
            client_id = user.id
            client = Client.objects.filter(id=client_id).first()
            if user.client.messaging == MessagingStatusChoices.ACTIVE.value:
                request.data['client'] = user.id
                request.data['from_type'] = FromTypes.CLIENT.value
            else:
                raise ValidationError('You are not allowed to message your provider yet')
        elif user.is_provider:
            client = Client.objects.filter(id=request.data['client']).first()
            if client:
                if client.messaging == MessagingStatusChoices.ACTIVE.value:
                    request.data['from_type'] = FromTypes.PROVIDER.value
                else:
                    raise ValidationError('Please update client messaging status to active')
            else:
                raise ValidationError('Client does not exist')

        message = ProviderClientMessage.objects.create(
            content=request.data.get('content'),
            client=client,
            from_type=request.data.get('from_type')
        )

        files = request.FILES
        for file in files:
            file_uri = ImageUpload.upload_image(files.get(file), 'message', str(message.pk), files.get(file).name)
            message.files.create(
                message_file=file_uri.split("?")[0],
                file_name=files.get(file).name
            )

        if user.is_client:
            client_message.send(sender=message, instance=message)
        if user.is_provider:
            provider_message.send(sender=message, instance=message, user=user)

        return Response({
            'id': message.id,
            'updated_at': message.updated_at,
            'created_at': message.created_at,
            'content': message.content,
            'files': [{
                'file_url': file.message_file,
                'file_name': file.file_name
            } for file in message.files.all()],
            'client': message.client.id,
            'message_type': message.message_type,
            'from_type': message.from_type,
            'is_read': message.is_read
        }, status=status.HTTP_201_CREATED)


@api_view(['GET'])
@authentication_classes([JWTAuthentication])
@permission_classes([IsProvider | IsClient])
@transaction.atomic
def mark_all_notifications(request):
    try:
        client_id = request.GET.get('client_id', None)

        if client_id:
            ProviderClientMessage.objects.filter(client__id=client_id).update(is_read=True)

        return Response(status=status.HTTP_201_CREATED)
    except Exception as e:
        return Response({
            'success': False,
            'message': f'Failed to read all notifications because of {str(e)}'
        }, status=status.HTTP_400_BAD_REQUEST)